#ifndef ECMASCRIPT_COMPILER_ASSEMBLER_RISCV64_H
#define ECMASCRIPT_COMPILER_ASSEMBLER_RISCV64_H

#include "ecmascript/compiler/assembler/assembler.h"
#include "ecmascript/compiler/assembler/riscv64/assembler_riscv64_constants.h"

namespace panda::ecmascript::riscv64 
{
	using namespace panda::ecmascript::base;
	
	class Register 
	{
		public:
			Register(RegisterId reg, RegisterType type = RegisterType::rd) : reg_(reg), type_(type) {};
			
			Register rd() const
			{
				return Register(reg_, RegisterType::rd);
			}

			Register rs1() const
			{
				return Register(reg_, RegisterType::rs1);
			}
			
			Register rs2() const
			{
				return Register(reg_, RegisterType::rs2);
			}
			
			RegisterType GetType() const
			{
				return type_;
			}
			
			inline RegisterId GetId() const
			{
				return reg_;
			}
			
		private:
			RegisterId reg_;
			RegisterType type_;
	};
	
	class Immediate 
	{
		public:
			Immediate(int32_t value) : value_(value) {}
			~Immediate() = default;

			int32_t Value() const
			{
				return value_;
			}
		private:
			int32_t value_;
	};
	
	class AssemblerRiscv64 : public Assembler 
	{
		public:
			explicit AssemblerRiscv64(Chunk *chunk)
			: Assembler(chunk)
			{
			}
			void Lui(const Register &rd, const Immediate& imm20);
			void Auipc(const Register &rd, const Immediate& imm20);	
			void Jal(const Register &rd, const Immediate& imm20);
		private:
			inline uint32_t Rd(uint32_t id){
				return (id << R_TYPE_rd_LOWBITS) & R_TYPE_rd_MASK;
			}
			inline uint32_t Rs1(uint32_t id){
				return (id << R_TYPE_rs1_LOWBITS) & R_TYPE_rs1_MASK;
			}
			inline uint32_t Rs2(uint32_t id){
				return (id << R_TYPE_rs2_LOWBITS) & R_TYPE_rs2_MASK;
			}
	};
}


#endif
